package com.xiaoshuidi.cloud.module.iot.service.impl.thirdPartImpl;

import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.AmmeterInfoResModel;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.WaterMeterCommonResponseModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.DeviceGetDailyPowerResModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceResponseModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenResponseModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenRequestModel;

import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.PullThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbDeviceDo;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbDoorlockPassword;
import com.xiaoshuidi.cloud.module.iot.dal.repository.TbDoorLockPasswordRepository;
import com.xiaoshuidi.cloud.module.iot.enums.*;
import com.xiaoshuidi.cloud.module.iot.service.AbstractThirdInstanceService;
import com.xiaoshuidi.cloud.module.iot.uitils.DateformatUtils;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import com.xiaoshuidi.cloud.module.iot.service.CacheService;

import org.springframework.util.CollectionUtils;

import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.regex.Pattern;

import static com.xiaoshuidi.cloud.module.iot.enums.BusinessConstant.DOOR_LOCK_PASSWORD_RECORD_STATUS_INVALID;
import static com.xiaoshuidi.cloud.module.iot.enums.BusinessConstant.TIMEOUT_TIP_MSG;
import static com.xiaoshuidi.cloud.module.iot.enums.KunShanPayloadFiledConstants.*;
import static com.xiaoshuidi.cloud.module.iot.uitils.DateformatUtils.ISO_DATE_FORMAT_PATTERN;

@Service("kunshanInstanceService")
@Slf4j
public class KunShanInstanceServiceImpl extends AbstractThirdInstanceService {

    @Override
    public String getBrand() {
        return BrandEnum.KUNSHAN.getBrand();
    }

    @Value("${kunshan.domain.name}")
    public String address;

    @Value("${kunshan.getToken.url}")
    public String tokenUrl;

    @Value("${kunshan.device.url}")
    public String deviceUrl;
    @Value("${kunshan.device.list.url}")
    public String deviceListUrl;

    @Autowired
    private CacheService cacheService;
    @Autowired
    private TbDoorLockPasswordRepository tbDoorLockPasswordDataAccess;

    @Override
    public AccessTokenResponseModel getAccessToken(AccessTokenRequestModel accessTokenRequestModel) throws Exception {
        AccessTokenResponseModel accessTokenResponseModel = new AccessTokenResponseModel();
        JSONObject param = new JSONObject();
        //密码 + "|" + "型号"
        String[] split = accessTokenRequestModel.getAppKey().split(Pattern.quote("|"));
        param.put("username", accessTokenRequestModel.getAppId());
        param.put("password", split[0]);
        param.put("channel", split[1]);
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
//        String result = HttpClientUtil.doPostJson(tokenUrl, param, header);
        String result = HttpRequest.post(tokenUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山获取token,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            JSONObject res = jsonObject.getJSONObject("data");
            if(null == res){
                return null;
            }
            accessTokenResponseModel.setAccessToken(res.getString("access_token"));
            accessTokenResponseModel.setExpireTime(res.getLong("expires_in")-100);
        }
        return accessTokenResponseModel;
    }

    @Override
    public List<TbDeviceDo> getDevice(PullThirdDeviceRequestModel pullThirdDeviceRequestModel) throws Exception {
        List<TbDeviceDo> tbDeviceDoList = Lists.newArrayList();
        String appAccount = pullThirdDeviceRequestModel.getLoginName();
        Map<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", pullThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", pullThirdDeviceRequestModel.getAccessToken());
        JSONObject bodyParam = new JSONObject();
        bodyParam.put("pageSize", 100);
        // 为获取全部项目,不传递项目名称
//        bodyParam.put("projectName", appAccount);
        //防止服务压力过大 最高20次拉去设备==
        for (int j = 1; j <= 20; j++) {
            bodyParam.put("pageIndex", j);
            log.info("琨山-拉取设备，请求url:{},请求头:{},请求参数:{}", deviceListUrl, header, bodyParam.toJSONString());
//            String result = HttpClientUtil.doPostJson(deviceListUrl, bodyParam, header);
            String result = HttpRequest.post(deviceListUrl).body(bodyParam.toJSONString()).addHeaders(header).execute().body();
            log.info("琨山-拉取设备,返回结果:{}", result);
            if (StringUtils.isNotBlank(result)) {
                JSONObject resultJson = JSONObject.parseObject(result);
                if (resultJson.getString("code").equals("200")) {
                    JSONArray dataJsonArray = resultJson.getJSONObject("data").getJSONArray("list");
                    if(dataJsonArray.isEmpty()){
                        break;
                    }
                    for (Iterator<Object> dataIterator = dataJsonArray.iterator(); dataIterator.hasNext(); ) {
                        JSONObject dataJsonObject = (JSONObject) dataIterator.next();
                        TbDeviceDo tbDeviceDo = new TbDeviceDo();
                        tbDeviceDo.setDeviceThirdNo(dataJsonObject.getString("lockId"));
                        tbDeviceDo.setDeviceName(dataJsonObject.getString("lockId"));
                        tbDeviceDo.setDeviceType(DeviceTypeEnum.DOORLOCK.getCode());
                        tbDeviceDo.setDeviceModel(BrandEnum.KUNSHAN.getBrand());
                        tbDeviceDo.setDeviceModel(dataJsonObject.getString("productModel"));
                        tbDeviceDo.setBatteryLevel(dataJsonObject.getDouble("batteryPercent"));
                        tbDeviceDo.setOnlineStatus(dataJsonObject.getInteger("state"));
                        tbDeviceDoList.add(tbDeviceDo);
                    }
                }
            }else {
                break;
            }
        }
        return tbDeviceDoList;
    }


    @Override
    public List<TbDeviceDo> initializeDeviceInfo(List<TbDeviceDo> thirdDeviceList, PullThirdDeviceRequestModel pullThirdDeviceRequestModel) {
        if (CollectionUtils.isEmpty(thirdDeviceList)) {
            log.error("没有设备需要进行初始化");
            return Collections.emptyList();
        }
        // 不在乎多大容量以及多少失败率,对失败操作做一个浅拷贝
        List<TbDeviceDo> failInitDevices = new LinkedList<>();
        HashMap<String, String> header = buildKunShanRpcCallHeader(pullThirdDeviceRequestModel.getLoginKey(), pullThirdDeviceRequestModel.getAccessToken());
        JSONObject param = new JSONObject();
        param.put(CMD_TYPE, INIT_CMD);
        for (TbDeviceDo oneDevice : thirdDeviceList) {
            // 第三方设备编号就是lockID
            String deviceThirdNo = oneDevice.getDeviceThirdNo();
            String deviceNo = oneDevice.getDeviceNo();
            param.put(LOCK_ID, deviceThirdNo);
//            String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
            String result = HttpRequest.post(deviceListUrl).body(param.toJSONString()).addHeaders(header).execute().body();
            // 返回值很简单 {code:200,msg:"success"}
            if (StringUtils.isBlank(result) || !result.contains(String.valueOf(HttpStatus.OK.value()))) {
                failInitDevices.add(oneDevice);
                log.error("对琨山设备进行初始化设备时发生错误,第三方设备编号{},返回内容 {}", oneDevice.getDeviceThirdNo(), result);
            } else {
                log.info("昆山门锁初始化成功,异步任务去失效所有的门锁信息");
                singleCoreThreadExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        //找到设备所有的密码
                        List<TbDoorlockPassword> doorLockPasswords = tbDoorLockPasswordDataAccess.findDoorLockPasswordByDeviceNo(deviceNo);
                        if (CollectionUtils.isEmpty(doorLockPasswords)) {
                            log.info("初始化设备{} 无需要失效的密码", deviceThirdNo);
                            return;
                        }
                        for (TbDoorlockPassword tbDoorlockPassword : doorLockPasswords) {
                            if (DOOR_LOCK_PASSWORD_RECORD_STATUS_INVALID == tbDoorlockPassword.getStatus()) {
                                continue;
                            }
                            TbDoorlockPassword updatePass = new TbDoorlockPassword();
                            updatePass.setStatus(DOOR_LOCK_PASSWORD_RECORD_STATUS_INVALID);
                            updatePass.setId(tbDoorlockPassword.getId());
                            tbDoorLockPasswordDataAccess.updateDoorLockPasswordRecordByCondition(updatePass);
                        }

                    }
                });
            }
        }
        return failInitDevices;
    }
    /**
     * 注意：
     * 指纹锁指纹内容在第三方有校验，不符合正确格式的指纹，在第三方会导致异常，进而影响在线密码的回调功能
     *
     * @param operateThirdDeviceRequestModel 第三方设备操作入参
     * @return 第三方操作响应
     */
    @Override
    public OperateThirdDeviceResponseModel addDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        if (operateThirdDeviceRequestModel.getPasswordType().equals("6")) {
            return addLXDoorLockPassword(operateThirdDeviceRequestModel);
        } else if (operateThirdDeviceRequestModel.getPasswordType().equals("2")) {
            return addZwPassword(operateThirdDeviceRequestModel);
        }
        return addZXDoorLockPassword(operateThirdDeviceRequestModel);
    }
    public OperateThirdDeviceResponseModel addZwPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) {
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        JSONObject param = new JSONObject();
        param.put("cmdType", "uploadFinger");
        param.put("lockId", operateThirdDeviceRequestModel.getDeviceThirdNo());
        param.put("startTime", operateThirdDeviceRequestModel.getPasswordStartTime() / 1000);
        param.put("endTime", operateThirdDeviceRequestModel.getPasswordEndTime() / 1000);
        param.put("finger", operateThirdDeviceRequestModel.getPasswordContent());
        param.put("requestId", operateThirdDeviceRequestModel.getPasswordId());
        // 1.普通用户 2.管理员
        param.put(KunShanPayloadFiledConstants.FINGER_TYPE, KunShanPayloadFiledConstants.FINGER_TYPE_RENTER);
        HashMap<String, String> header = buildKunShanRpcCallHeader(operateThirdDeviceRequestModel);
//        String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
        String result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山添加指纹密码,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                // 指纹密码有回调功能
                operateThirdDeviceResponseModel.setPasswordStatus(4);
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }
    public OperateThirdDeviceResponseModel addLXDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) {
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        JSONObject param = new JSONObject();
        param.put("cmdType", "getOfflinePass");
        param.put("lockId", operateThirdDeviceRequestModel.getDeviceThirdNo());
        param.put("startTime", DateformatUtils.formatDate(new Date(operateThirdDeviceRequestModel.getPasswordStartTime()), "yyyy-MM-dd"));
        Date date = new Date(operateThirdDeviceRequestModel.getPasswordEndTime());
        date.setMinutes(0);
        date.setSeconds(0);
        param.put("endTime", DateformatUtils.formatDate(date, "yyyy-MM-dd HH:mm:ss"));
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", operateThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", operateThirdDeviceRequestModel.getAccessToken());
//        String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
        String result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山获取离线密码,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setPasswordStatus(1);
                operateThirdDeviceResponseModel.setPasswordContent(jsonObject.getJSONObject("data").getString("pass"));
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }
    public OperateThirdDeviceResponseModel addZXDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel)  {
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        JSONObject param = new JSONObject();
        param.put("cmdType", "setUserPass");
        param.put("lockId", operateThirdDeviceRequestModel.getDeviceThirdNo());
        param.put("controlflag", 1);
        param.put("startTime", operateThirdDeviceRequestModel.getPasswordStartTime() / 1000);
        param.put("endTime", operateThirdDeviceRequestModel.getPasswordEndTime() / 1000);
        param.put("pass", operateThirdDeviceRequestModel.getPasswordContent());
        param.put("id", operateThirdDeviceRequestModel.getPasswordId());
        operateThirdDeviceResponseModel.setThirdPassId(operateThirdDeviceRequestModel.getPasswordId());
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", operateThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", operateThirdDeviceRequestModel.getAccessToken());
//        String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
        String result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山添加在线密码,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setPasswordStatus(4);
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }
    /**
     * 琨山门锁一个小时内仅有12个一次性密码
     *
     * @param operateThirdDeviceRequestModel 请求参数
     * @return 响应内容
     * @throws Exception 受检异常中的问题
     */

    @Override
    public OperateThirdDeviceResponseModel getDynamicDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        int dynamicPasswordIndex = getDynamicPasswordIndex(operateThirdDeviceRequestModel.getDeviceThirdNo());
        if (dynamicPasswordIndex == -1) {
            log.error("当前时段内的动态密码已使用完毕");
            operateThirdDeviceResponseModel.setOperateMessage("当前时段内的动态密码已使用完毕");
            return operateThirdDeviceResponseModel;
        }
        JSONObject param = new JSONObject();
        param.put("cmdType", "getOncePass");
        param.put("lockId", operateThirdDeviceRequestModel.getDeviceThirdNo());
        param.put("index", dynamicPasswordIndex);
        Date date = new Date();
        date.setMinutes(0);
        date.setSeconds(0);
        param.put("startTime", DateformatUtils.formatDate(date, "yyyy-MM-dd HH:mm:ss"));
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", operateThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", operateThirdDeviceRequestModel.getAccessToken());
//        String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
        String result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山动态密码,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setPasswordContent(jsonObject.getJSONObject("data").getString("pass"));
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }

    @Override
    public AmmeterInfoResModel refreshAmmeterInfo(TbDeviceDo tbDeviceDo, OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public List<DeviceGetDailyPowerResModel> getDailyPower(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel updateDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        JSONObject param = new JSONObject();
        param.put("cmdType", "setUserPass");
        param.put("lockId", operateThirdDeviceRequestModel.getDeviceThirdNo());
        param.put("controlflag", 0);
        param.put("startTime", operateThirdDeviceRequestModel.getPasswordStartTime() / 1000);
        param.put("endTime", operateThirdDeviceRequestModel.getPasswordEndTime() / 1000);
        param.put("pass", operateThirdDeviceRequestModel.getPasswordContent());
        param.put("index", operateThirdDeviceRequestModel.getTbDoorlockPassword().getThirdPasswordId());
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", operateThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", operateThirdDeviceRequestModel.getAccessToken());
        String passwordType = operateThirdDeviceRequestModel.getPasswordType();
        // 指纹密码的修改
        String result;
        if (PasswordTypeEnum.FINGER_DIGIT.getTypeCode().equals(passwordType)) {
            result = updateFingerPrintEffectiveDate(operateThirdDeviceRequestModel, header);
        } else {
//            result = HttpClientUtil.doPostJson(deviceUrl, param, header);
            result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        }
        log.info("琨山修改密码,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setPasswordStatus(4);
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }

    @Override
    public OperateThirdDeviceResponseModel frozenDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        String passwordType = operateThirdDeviceRequestModel.getPasswordType();
        String cmdType = "passFreezeControl";
        if (PasswordTypeEnum.FINGER_DIGIT.getTypeCode().equals(passwordType)) {
            cmdType = "fingerFreezeControl";
        }
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        JSONObject param = new JSONObject();
        param.put("cmdType", cmdType);
        param.put("lockId", operateThirdDeviceRequestModel.getDeviceThirdNo());
        param.put("freeze", 1);
        param.put("index", Integer.valueOf(operateThirdDeviceRequestModel.getTbDoorlockPassword().getThirdPasswordId()));
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", operateThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", operateThirdDeviceRequestModel.getAccessToken());
//        String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
        String result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山冻结密码,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setPasswordStatus(4);
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }

    @Override
    public OperateThirdDeviceResponseModel unfrozenDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        String passwordType = operateThirdDeviceRequestModel.getPasswordType();
        String cmdType = "passFreezeControl";
        if (PasswordTypeEnum.FINGER_DIGIT.getTypeCode().equals(passwordType)) {
            cmdType = "fingerFreezeControl";
        }
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        JSONObject param = new JSONObject();
        param.put("cmdType", cmdType);
        param.put("lockId", operateThirdDeviceRequestModel.getDeviceThirdNo());
        param.put("freeze", 0);
        param.put("index", Integer.valueOf(operateThirdDeviceRequestModel.getTbDoorlockPassword().getThirdPasswordId()));
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", operateThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", operateThirdDeviceRequestModel.getAccessToken());
//        String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
        String result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山解冻密码,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setPasswordStatus(4);
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }

    @Override
    public OperateThirdDeviceResponseModel switchAmmeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchAmmeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel deleteDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        String passwordType = operateThirdDeviceRequestModel.getPasswordType();
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        JSONObject param = new JSONObject();
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", operateThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", operateThirdDeviceRequestModel.getAccessToken());
        // 琨山离线密码清除api
        // 该api同步响应，不会发生回调
        if (PasswordTypeEnum.OFFLINE_PASSWORD.getTypeCode().equals(passwordType)) {
            long startTime = operateThirdDeviceRequestModel.getTbDoorlockPassword().getCreateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            return deleteOfflinePassword(header,startTime,
                    operateThirdDeviceRequestModel.getDeviceThirdNo(),
                    operateThirdDeviceRequestModel.getDeviceNo(), operateThirdDeviceRequestModel.getPasswordId());
        }
        param.put(LOCK_ID, operateThirdDeviceRequestModel.getDeviceThirdNo());
        param.put(PASSWD_INDEX, operateThirdDeviceRequestModel.getTbDoorlockPassword().getThirdPasswordId());
        // 琨山指纹删除api
        if (PasswordTypeEnum.FINGER_DIGIT.getTypeCode().equals(passwordType)) {
            param.put(KunShanPayloadFiledConstants.CMD_TYPE, KunShanPayloadFiledConstants.DELETE_FINGER_CMD);
        } else {
            param.put("controlflag", 16);
            param.put("cmdType", "setUserPass");
        }
//        String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
        String result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山删除密码,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                operateThirdDeviceResponseModel.setPasswordStatus(4);
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }

    @Override
    public WaterMeterCommonResponseModel refreshWatermeterInfo(WaterMeterCommonResponseModel waterMeterCommonResponseModel, OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel getDoorLockStatus(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        OperateThirdDeviceResponseModel operateThirdDeviceResponseModel = new OperateThirdDeviceResponseModel();
        operateThirdDeviceResponseModel.setOperateResult(false);
        JSONObject param = new JSONObject();
        param.put("cmdType", "getLockInfo");
        param.put("lockId", operateThirdDeviceRequestModel.getDeviceThirdNoList().get(0));
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", operateThirdDeviceRequestModel.getLoginKey().split(Pattern.quote("|"))[1]);
        header.put("authorization", operateThirdDeviceRequestModel.getAccessToken());
//        String result = HttpClientUtil.doPostJson(deviceUrl, param, header);
        String result = HttpRequest.post(deviceUrl).body(param.toJSONString()).addHeaders(header).execute().body();
        log.info("琨山刷新门锁,请求参数:{},返回结果:{}", param, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getString("code").equals("200")) {
                operateThirdDeviceResponseModel.setOperateResult(true);
                JSONObject data = jsonObject.getJSONObject("data");
                operateThirdDeviceResponseModel.setBatteryLevel(data.getDouble("battery"));
                // todo 按照琨山说法，online这个字段不准确的，按updateTime离当前时间未超过24小时就认为是在线的 ,后续若有必要再进行调整
                Integer online = data.getInteger("online");
                if(null == online){
                    online = 0;
                }
                operateThirdDeviceResponseModel.setOnlineStatus(online);
            } else {
                operateThirdDeviceResponseModel.setOperateMessage(jsonObject.getString("msg"));
            }
        }
        return operateThirdDeviceResponseModel;
    }

    @Override
    public OperateThirdDeviceResponseModel getOpenLockRecordes(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchColdWaterMeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchHotWaterMeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchHotWaterMeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchColdWaterMeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }
    /**
     * 前端请求->琨山api服务->响应离线期限密码清除码->终端用户在锁上执行 清除码# 指令进行清楚
     *
     * @param headers       请求头
     * @param startTime     前端传递的时间毫秒数
     * @param deviceThirdNo 第三方设备号
     * @return 重要参数 清楚码
     */
    protected OperateThirdDeviceResponseModel deleteOfflinePassword(@NonNull HashMap<String, String> headers, @NonNull long startTime, @NonNull String deviceThirdNo, @NonNull String deviceNo, @NonNull String thirdPassId) {
        JSONObject payLoad = new JSONObject();
        payLoad.put(LOCK_ID, deviceThirdNo);
        payLoad.put(CMD_TYPE, DELETE_OFFLINE_PASSWD);
        // api中必须指定起始日期，yyyy-MM-dd 格式
        payLoad.put(START_TIME_ISO_DATE, DateformatUtils.formatDate(new Date(startTime), ISO_DATE_FORMAT_PATTERN));
//        String result = HttpClientUtil.doPostJson(deviceUrl, payLoad, headers);
        String result = HttpRequest.post(deviceUrl).body(payLoad.toJSONString()).addHeaders(headers).execute().body();
        log.info("琨山删除密码,请求地址:{},请求参数:{},请求头:{},返回结果:{}", deviceUrl, payLoad, headers, result);
        JSONObject respJson = JSONObject.parseObject(result);
        OperateThirdDeviceResponseModel responseModel = new OperateThirdDeviceResponseModel();
        // 网咯超时等原因导致未收到结果
        if (Objects.isNull(respJson)) {
            responseModel.setOperateMessage(TIMEOUT_TIP_MSG);
            return responseModel;
        }
        if (String.valueOf(HttpStatus.OK.value()).equals(respJson.getString(RESP_CODE))) {
            // 因为没有回调，直接将 tb_doorlock_password 状态设置未失效
            TbDoorlockPassword tbDoorlockPassword = new TbDoorlockPassword();
            tbDoorlockPassword.setThirdPasswordId(thirdPassId);
            tbDoorlockPassword.setStatus(DOOR_LOCK_PASSWORD_RECORD_STATUS_INVALID);
            tbDoorlockPassword.setDeviceNo(deviceNo);
            tbDoorlockPassword.setAuthType(Integer.parseInt(PasswordTypeEnum.OFFLINE_PASSWORD.getTypeCode()));
            tbDoorLockPasswordDataAccess.updateDoorLockPasswordRecordByCondition(tbDoorlockPassword);
            responseModel.setOperateResult(true);
            responseModel.setPasswordCode(respJson.getJSONObject(RESP_DATA).getString(RESP_DATA_PASS));
        } else {
            responseModel.setOperateMessage(respJson.getString(RESP_MSG));
        }
        return responseModel;
    }

    /**
     * 修改指纹剩下时间
     *
     * @param operateThirdDeviceRequestModel 请求参数
     * @param headers                        请求头
     * @return rpc 响应
     */
    public String updateFingerPrintEffectiveDate(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel, Map<String, String> headers) {
        JSONObject content = new JSONObject();
        content.put(CMD_TYPE, UPDATE_FINGER_CMD);
        content.put(LOCK_ID, operateThirdDeviceRequestModel.getDeviceThirdNo());
        content.put(START_TIME_SECONDS, operateThirdDeviceRequestModel.getPasswordStartTime() / 1000);
        content.put(END_TIME_SECONDS, operateThirdDeviceRequestModel.getPasswordEndTime() / 1000);
        content.put(PASSWD_INDEX, operateThirdDeviceRequestModel.getTbDoorlockPassword().getThirdPasswordId());
//        return HttpClientUtil.doPostJson(deviceUrl, content, headers);
        return HttpRequest.post(deviceUrl).body(content.toJSONString()).addHeaders(headers).execute().body();
    }

    /**
     * 获取当前小时内的该设备获取到第多少个一次性密码
     * 使用redis保存，按照现有的逻辑一次性密码不保存数据库中
     *
     * @param deviceThirdNo 第三方设备号
     * @return 0-11 正常值，-1 表示本设备在该小时内不再支持一次性密码
     */
    public int getDynamicPasswordIndex(String deviceThirdNo) throws Exception {
        int maxLimit = 11;
        LocalTime now = LocalTime.now();
        int hour = now.getHour();
        int minute = now.getMinute();
        // 当前小时数做key,即使有临界时间也不影响，但可能会存在跨度，即获取到第三方的下一小时的数据，会导致下一小时获取时出现密码已经被使用
        String key = new StringBuilder().append(RedisTypeEnum.SDIOT_DYNAMICDOORLOCK.getCode()).append(deviceThirdNo).append(hour).toString();
        String indexToken = cacheService.getString(key);
        if (StringUtils.isBlank(indexToken)) {
            cacheService.putString(key, "0", (60 - minute + 1) * 60);
            return 0;
        } else {
            int lastIndex = Integer.parseInt(indexToken);
            if (lastIndex == maxLimit) {
                return -1;
            } else {
                cacheService.putString(key, String.valueOf(lastIndex + 1), (60 - minute + 1) * 60);
                return lastIndex + 1;
            }
        }
    }
    private HashMap<String, String> buildKunShanRpcCallHeader(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) {
        return buildKunShanRpcCallHeader(operateThirdDeviceRequestModel.getLoginKey(), operateThirdDeviceRequestModel.getAccessToken());
    }

    private HashMap<String, String> buildKunShanRpcCallHeader(String loginKey, String authorization) {
        HashMap<String, String> header = Maps.newHashMap();
        header.put("Content-Type", "application/json");
        header.put("channel", loginKey.split(Pattern.quote("|"))[1]);
        header.put("authorization", authorization);
        return header;
    }
}
